package com.atguigu.tingshu.album.service.impl;

import com.atguigu.tingshu.album.mapper.AlbumAttributeValueMapper;
import com.atguigu.tingshu.album.mapper.AlbumInfoMapper;
import com.atguigu.tingshu.album.mapper.AlbumStatMapper;
import com.atguigu.tingshu.album.service.AlbumInfoService;
import com.atguigu.tingshu.common.cache.TsCache;
import com.atguigu.tingshu.common.constant.RedisConstant;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.rabbit.constant.MqConst;
import com.atguigu.tingshu.common.rabbit.service.RabbitService;
import com.atguigu.tingshu.model.album.AlbumAttributeValue;
import com.atguigu.tingshu.model.album.AlbumInfo;
import com.atguigu.tingshu.model.album.AlbumStat;
import com.atguigu.tingshu.query.album.AlbumInfoQuery;
import com.atguigu.tingshu.vo.album.AlbumAttributeValueVo;
import com.atguigu.tingshu.vo.album.AlbumInfoVo;
import com.atguigu.tingshu.vo.album.AlbumListVo;
import com.atguigu.tingshu.vo.album.AlbumStatVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tencentcloudapi.captcha.v20190722.models.CaptchaUserAllAppId;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.Nullable;
import org.redisson.api.RBloomFilter;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.List;
import java.util.Random;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service
@SuppressWarnings({"all"})

/**
 * @author WeakMoon
 * @date 2025/02/19 00:47:12
 * AlbumInfoServiceImpl 类实现了 AlbumInfoService 接口，提供了专辑信息的保存和统计信息的管理功能。
 */

public class AlbumInfoServiceImpl extends ServiceImpl<AlbumInfoMapper, AlbumInfo> implements AlbumInfoService {

	@Autowired
	private AlbumInfoMapper albumInfoMapper;

	@Autowired
	private AlbumStatMapper albumStatMapper;

	@Autowired
	private AlbumAttributeValueMapper albumAttributeValueMapper;

	@Autowired
	private RabbitService rabbitService;

	@Autowired
	private RedisTemplate redisTemplate;

	@Autowired
	private RedissonClient redissonClient;

	/**
	 * @author WeakMoon
	 * @date 2025/02/21 20:48:36
	 * 获取当前用户全部专辑列表
	 */
	@Override
	public List<AlbumInfo> findUserAllAlbumList(Long userId) {
		//return albumInfoMapper.selectList(new LambdaQueryWrapper<AlbumInfo>().eq(AlbumInfo::getUserId,userId));
		//分页返回，提高响应速度
		Page<AlbumInfo> albumInfoPage = new Page<>(1,10);
		Page<AlbumInfo> infoPage = albumInfoMapper.selectPage(albumInfoPage,new LambdaQueryWrapper<AlbumInfo>().eq(AlbumInfo::getUserId,userId).select(AlbumInfo::getId,AlbumInfo::getAlbumTitle).orderByDesc(AlbumInfo::getId));
		return infoPage.getRecords();
	}

	/**
	 * @author WeakMoon
	 * @date 2025/02/21 19:43:04
	 * 完成专辑的列表功能-修改用户专辑列表：更新专辑对象数据
	 */
	@Override
	public void updateAlbumInfo(Long albumId, AlbumInfoVo albumInfoVo) {
	    // 创建一个新的专辑信息对象
	    AlbumInfo albumInfo = new AlbumInfo();
	    // 将传入的专辑信息Vo对象属性复制到专辑信息对象
	    BeanUtils.copyProperties(albumInfoVo,albumInfo);
	    // 设置专辑信息对象的ID为传入的专辑ID
	    albumInfo.setId(albumId);
	    // 更新数据库中的专辑信息
	    albumInfoMapper.updateById(albumInfo);
	    // 删除数据库中与当前专辑ID相关的所有专辑属性值
	    albumAttributeValueMapper.delete(new LambdaQueryWrapper<AlbumAttributeValue>().eq(AlbumAttributeValue::getAlbumId,albumId));

	    // 获取传入的专辑属性值Vo列表
	    List<AlbumAttributeValueVo> albumAttributeValueVoList = albumInfoVo.getAlbumAttributeValueVoList();
	    // 检查专辑属性值Vo列表是否不为空
	    if (!CollectionUtils.isEmpty(albumAttributeValueVoList)){
	        // 遍历专辑属性值Vo列表
	        for (AlbumAttributeValueVo albumAttributeValueVo : albumAttributeValueVoList) {
	            // 创建一个新的专辑属性值对象
	            AlbumAttributeValue albumAttributeValue = new AlbumAttributeValue();
	            // 将专辑属性值Vo对象属性复制到专辑属性值对象
	            BeanUtils.copyProperties(albumAttributeValueVo,albumAttributeValue);
	            // 设置专辑属性值对象的专辑ID为专辑信息对象的ID
	            albumAttributeValue.setAlbumId(albumInfo.getId());
	            // 插入新的专辑属性值到数据库
	            albumAttributeValueMapper.insert(albumAttributeValue);
	        }
	    }
		//判断专辑上架、下架
		if ("1".equals(albumInfoVo.getIsOpen())){
			// 专辑上架
			rabbitService.sendMessage(MqConst.EXCHANGE_ALBUM,MqConst.ROUTING_ALBUM_UPPER,albumId);
			// 添加到布隆过滤器
			RBloomFilter<Object> bloomFilter = redissonClient.getBloomFilter(RedisConstant.ALBUM_BLOOM_FILTER);
			// 将专辑Id添加到过滤器中
			bloomFilter.add(albumId);

		}else {
			//专辑下架
			rabbitService.sendMessage(MqConst.EXCHANGE_ALBUM,MqConst.ROUTING_ALBUM_LOWER,albumId);
		}
	}

	/**
	 * @author WeakMoon
	 * @date 2025/02/21 19:10:14
	 * 完成专辑的列表功能-修改用户专辑列表：根据专辑id获取专辑对象数据
	 */
	@Override
	@TsCache(prefix = RedisConstant.ALBUM_INFO_PREFIX)
	public AlbumInfo getAlbumInfo(Long albumId) {
//	    // 构造缓存键
//	    String dataKey = RedisConstant.ALBUM_INFO_PREFIX + albumId;
//	    try {
//	        // 尝试从缓存中获取专辑信息
//	        AlbumInfo albumInfo = (AlbumInfo) this.redisTemplate.opsForValue().get(dataKey);
//	        if (null == albumInfo){
//	            // 如果缓存中没有数据，使用分布式锁防止缓存击穿
//	            String lockKey = RedisConstant.ALBUM_LOCK_SUFFIX + albumId;
//	            RLock lock = redissonClient.getLock(lockKey);
//
//	            lock.lock();
//	            try {
//	                // 再次尝试从缓存中获取专辑信息，以防止在等待锁期间数据被其他线程写入
//	                albumInfo = (AlbumInfo) this.redisTemplate.opsForValue().get(dataKey);
//	                if (null != albumInfo){
//	                    log.info("查询缓存");
//	                    return albumInfo;
//	                }
//	                // 从数据库中获取专辑信息
//	                albumInfo = getAlbumInfoDB(albumId);
//	                log.info("查询数据库");
//	                if (null == albumInfo){
//	                    // 如果数据库中也没有数据，设置一个空的专辑信息到缓存，防止缓存雪崩
//	                    this.redisTemplate.opsForValue().set(dataKey,new AlbumInfo(),10, TimeUnit.MINUTES);
//	                    return new AlbumInfo();
//	                }
//	                // 将从数据库中获取到的数据写入缓存
//	                this.redisTemplate.opsForValue().set(dataKey,albumInfo,RedisConstant.ALBUM_TIMEOUT,TimeUnit.SECONDS);
//	                return albumInfo;
//	            } catch (Exception e) {
//	                throw new RuntimeException(e);
//	            } finally {
//	                // 释放锁
//	                lock.unlock();
//	            }
//	        }else {
//	            log.info("查询缓存");
//	            return albumInfo;
//	        }
//	    } catch (RuntimeException e) {
//	        // 处理运行时异常
//	        System.out.println(e.getMessage());
//	    }
	    // 如果以上步骤都未能获取到专辑信息，则从数据库中获取
	    return getAlbumInfoDB(albumId);
	}

	private @Nullable AlbumInfo getAlbumInfoDB(Long albumId) {
		// 根据专辑ID获取专辑信息
		AlbumInfo albumInfo = this.getById(albumId);
		// 如果获取到的专辑信息不为空
		if (albumInfo != null){
			// 设置专辑属性值列表，通过专辑ID查询关联的专辑属性值
			albumInfo.setAlbumAttributeValueVoList(albumAttributeValueMapper.selectList(new LambdaQueryWrapper<AlbumAttributeValue>().eq(AlbumAttributeValue::getAlbumId, albumId)));
		}
		// 返回专辑信息对象，可能包含专辑属性值列表
		return albumInfo;
	}

	/**
	 * @author WeakMoon
	 * @date 2025/02/21 17:24:35
	 * 完成专辑的列表功能-删除专辑列表
	 * 相关表：album_attribute_value，album_info，album_stat
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public void removeAlbumInfo(Long albumId) {
		//删除专辑信息
		albumInfoMapper.deleteById(albumId);

		//删除与其相关的属性值信息
		//delete from album_attribute_value where album_id = ? and is_delete=0; 物理删除;
		//update album_attribute_value set is_delete=1 where album_id = ? and is_delete=0; 逻辑删除
		albumAttributeValueMapper.delete(new LambdaQueryWrapper<AlbumAttributeValue>().eq(AlbumAttributeValue::getAlbumId,albumId));

		//删除与其相关的统计信息
		albumStatMapper.delete(new LambdaQueryWrapper<AlbumStat>().eq(AlbumStat::getAlbumId,albumId));
	}

	/**
	 * @author WeakMoon
	 * @date 2025/02/19 14:36:38
	 * 完成专辑的列表功能-分页查询用户专辑列表
	 */
	@Override
	public IPage<AlbumListVo> findUserAlbumPage(Page<AlbumListVo> albumListVoPage, AlbumInfoQuery albumInfoQuery) {
		//查询数据有专辑的基本信息，专辑的统计信息（album_info，album_stat）
		return albumInfoMapper.selectUserAlbumPage(albumListVoPage,albumInfoQuery);
	}

	/**
	 * 保存专辑信息及其相关属性值，并初始化专辑的统计信息。
	 * 若是批量保存：借助ServiceImpl 实现类：this.saveBatch（）；
	 * @param albumInfoVo 专辑信息视图对象，包含专辑的基本信息和属性值列表。
	 * @param userId 用户ID，表示创建该专辑的用户。
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public void saveAlBumInfo(AlbumInfoVo albumInfoVo, Long userId) {
		// 创建专辑信息对象，并将视图对象的属性拷贝到实体对象中
		AlbumInfo albumInfo = new AlbumInfo();

		// 属性赋值; 属性拷贝（属性一致的；将属性数据平移）
		BeanUtils.copyProperties(albumInfoVo, albumInfo);

		// 设置专辑的用户ID
		albumInfo.setUserId(userId);

		// 如果专辑的支付类型不是免费，则设置免费试听的曲目数量
		if (!SystemConstant.ALBUM_PAY_TYPE_FREE.equals(albumInfoVo.getPayType())) {
			albumInfo.setTracksForFree(5);
		}

		// 设置专辑的状态
		albumInfo.setStatus(SystemConstant.ALBUM_STATUS_PASS);

		// 将专辑信息插入数据库
		albumInfoMapper.insert(albumInfo);

		// 处理专辑属性值列表
		List<AlbumAttributeValueVo> albumAttributeValueVoList = albumInfoVo.getAlbumAttributeValueVoList();
		// 判断
		if (!CollectionUtils.isEmpty(albumAttributeValueVoList)) {
			for (AlbumAttributeValueVo albumAttributeValueVo : albumAttributeValueVoList) {
				// 创建对象
				AlbumAttributeValue albumAttributeValue = new AlbumAttributeValue();
				// 属性拷贝
				BeanUtils.copyProperties(albumAttributeValueVo, albumAttributeValue);
				// 因为71行执行了insert 方法。所以通过type = IdType.AUTO 属性配置，就能够获取到主键自增的id
				albumAttributeValue.setAlbumId(albumInfo.getId());
				// 保存数据：insert into album_attribute_value values(?,?,?);
				albumAttributeValueMapper.insert(albumAttributeValue);
			}
		}

		// 初始化专辑的统计信息
		this.saveAlbumStat(albumInfo.getId(), SystemConstant.ALBUM_STAT_PLAY);
		this.saveAlbumStat(albumInfo.getId(), SystemConstant.ALBUM_STAT_SUBSCRIBE);
		this.saveAlbumStat(albumInfo.getId(), SystemConstant.ALBUM_STAT_BROWSE);
		this.saveAlbumStat(albumInfo.getId(), SystemConstant.ALBUM_STAT_COMMENT);

		if ("1".equals(albumInfoVo.getIsOpen())) {
			//	上架 需要专辑Id;
			rabbitService.sendMessage(MqConst.EXCHANGE_ALBUM, MqConst.ROUTING_ALBUM_UPPER, albumInfo.getId());
			//  添加到布隆过滤器;
			RBloomFilter<Object> bloomFilter = redissonClient.getBloomFilter(RedisConstant.ALBUM_BLOOM_FILTER);
			//  将专辑Id添加到过滤器中
			bloomFilter.add(albumInfo.getId());
		}
	}


	/**
	 * 保存专辑的统计信息。
	 * @param albumId 专辑ID，表示统计信息所属的专辑。
	 * @param statPlay 统计类型，表示统计的具体类型（如播放、订阅等）。
	 */
	public void saveAlbumStat(Long albumId, String statPlay) {
		AlbumStat albumStat = new AlbumStat();
		albumStat.setAlbumId(albumId);
		albumStat.setStatType(statPlay);
		albumStat.setStatNum(new Random().nextInt(10000000));
		albumStatMapper.insert(albumStat);
	}


}
